package priv.abadstring.study.haoke.webapi.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import graphql.ExecutionInput;
import graphql.GraphQL;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * GraphQLController
 *
 * @author aBadString
 * @date 2021-06-17 19:53:10
 */
@Slf4j
@RestController
@RequestMapping("graphql")
@CrossOrigin
public class GraphQLController {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private final GraphQL graphQL;
    public GraphQLController(GraphQL graphQL) {
        this.graphQL = graphQL;
    }

    private Map<String, Object> executeGraphqlQuery(String query, String operationName, Map<String, Object> variables) {
        ExecutionInput executionInput = ExecutionInput.newExecutionInput()
                .query(query)
                .operationName(operationName)
                .variables(variables)
                .build();
        return this.graphQL.execute(executionInput).toSpecification();
    }


    @GetMapping
    public Map<String, Object> graphql(
            @RequestParam("query") String query,
            @RequestParam(value = "variables", required = false) String variablesJson,
            @RequestParam(value = "operationName", required = false) String operationName) {
        log.debug("query: " + query + ", variablesJson: " + variablesJson + ", operationName: " + operationName);
        try {
            Map<String, Object> variables;
            if (variablesJson == null) {
                variables = Collections.EMPTY_MAP;
            } else {
                variables = OBJECT_MAPPER.readValue(
                        variablesJson,
                        OBJECT_MAPPER.getTypeFactory().constructMapType(HashMap.class, String.class, Object.class)
                );
            }
            return this.executeGraphqlQuery(query, operationName, variables);
        } catch (IOException e) {
            e.printStackTrace();
            return new HashMap<String, Object>() {
                {
                    this.put("status", 500);
                    this.put("msg", "查询出错");
                }
            };
        }
    }

    @PostMapping
    public Map<String, Object> postGraphql(@RequestBody Map<String,Object> map) {
        log.debug("map: " + map);

        try {
            String query = (String) map.get("query");
            if(null == query){
                query = "";
            }
            String operationName = (String) map.get("operationName");
            Map<String, Object> variables = (Map<String, Object>) map.get("variables");
            if(variables == null){
                variables = Collections.EMPTY_MAP;
            }
            return this.executeGraphqlQuery(query, operationName, variables);
        } catch (Exception e) {
            e.printStackTrace();
            return new HashMap<String, Object>() {
                {
                    this.put("status", 500);
                    this.put("msg", "查询出错");
                }
            };
        }
    }
}
